package bingo.codeweaver.core.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Random;

import net.bingosoft.common.resource.ResourceManager;
import net.bingosoft.common.util.StringHelper;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.springframework.core.io.ClassPathResource;

/**
 * 
 * 2007-8-21 上午10:46:40
 * Author:yangdongyu(yangdy@bingosoft.net)
 * ReadMe:
 * ChangeLog:
 */
public final class FileHelper {

	private static final Log log = LogFactory.getLog(FileHelper.class);
	private static Properties properties;
	/**
	 * 导出或下载时文件名称编码
	 */
	public static final String EXPORTED_FILE_NAME_ENCODING = "ISO-8859-1";


	/**
	 * 读取输入流中的内容
	 * @param in
	 * @param encoding
	 * @return
	 */
	public static String readStreamContent(InputStream in,String encoding){
		String content = "";
		try{
			InputStreamReader reader = null;
			try {
				if(StringUtils.isEmpty(encoding)){
					reader = new InputStreamReader(in);
				}else{
					reader = new InputStreamReader(in,encoding);	
				}

				StringBuffer sb = new StringBuffer();
				int b;
				while ((b = reader.read()) != -1) {
					sb.append((char)b);             
				}
				content = sb.toString();
			} finally {
				try {
					reader.close();
				} catch (Exception e) {
					;
				}
			}
		}catch(IOException e){
			log.error(e);
		}finally{
			try {
				in.close();
			} catch (IOException e) {
				;
			}
		}    
		return content;
	}
	/**
	 * 读取给定文件的文件内容
	 * @param filePath
	 * @return
	 * @throws FileNotFoundException
	 */
	public static String readFileContent(String filePath) throws FileNotFoundException{
		filePath = StringHelper.replace(filePath,"\\","/");
		return readStreamContent(new FileInputStream(filePath), "GBK");
	}
	
	/**
	 * 读取给定文件的文件内容
	 * @param filePath
	 * @return
	 * @throws FileNotFoundException
	 */
	public static String readFileContent(String filePath,String encoding) throws FileNotFoundException{
		filePath = StringHelper.replace(filePath,"\\","/");
		return readStreamContent(new FileInputStream(filePath), encoding);
	}
	/**
	 * 删除给定路径上的文件
	 * @param absolutePath 文件的绝对路径
	 * @return 文件是否删除成功
	 */
	public static boolean deleteFile(String absolutePath){
		File f = new File(absolutePath);
		if(f.exists() && f.isFile()){
			return f.delete();
		}
		return false;
	}
	/**
	 * 根据文件名获取文件的扩展名，如果没有扩展名，返回""
	 * @param fileName 不带路径或者带路径的文件名
	 * @return
	 */
	public static String getFileExtName(String fileName){
		int extIndex    = fileName.lastIndexOf(".");
		String fileExt  = extIndex > 0 ? fileName.substring(extIndex+1) : "";        
		return fileExt;
	}

	/**
	 * 根据文件路径获取不包含扩展名的文件名
	 * @param filePath 带路径的文件名
	 * @return
	 */
	public static String getFileNameElimExt(String filePath){
		String fileName = getFileName(filePath).trim();
		if( fileName.length() > 0){
			int extLength = getFileExtName(fileName).length();    		
			fileName = extLength >0 ? fileName.substring(0,fileName.length()- extLength - 1) : fileName;
		}
		return fileName;
	}

	/**
	 * 根据文件路径获取文件名
	 * @param filePath 带路径的文件名
	 * @return
	 */
	public static String getFileName(String filePath){
		filePath = StringHelper.replace(filePath,"\\","/");
		int lastFolderIndex = filePath.lastIndexOf("/");
		String fileName     = lastFolderIndex > 0 ? filePath.substring(lastFolderIndex+1) : filePath; 
		return fileName;
	}

	/**
	 * 根据文件全路径获取文件所在目录的全路径
	 * @param file
	 * @return
	 */
	public static String getFileFolder(String file){
		file = StringHelper.replace(file,"\\","/");
		return file.substring(0,file.lastIndexOf("/"));

	}    

	/**
	 * 创建一个文件，把输入流的内容写入指定的文件中,如果文件所在目录不存在,会自动被创建
	 * @param file
	 * @param in
	 * @throws IOException
	 */
	public static void createFile(String file,InputStream in) throws IOException{

		createFolder(getFileFolder(file));
		FileOutputStream out = new FileOutputStream(file);
		try{
			byte[] bytes = new byte[1024];
			int n = -1 ;
			while(( n = in.read(bytes)) != -1){
				out.write(bytes,0,n);
			}
			return;
		}finally{
			try{
				in.close(); 
				out.flush();
				out.close();        
			}catch(Throwable e){}
		}

	}    

	/**
	 * 创建一个文件，把文件内容写入指定的文件中
	 * 
	 * <p>如果文件所在目录不存在，会自动被创建
	 * @param file
	 * @param in
	 * @throws IOException
	 */
	public static void createFile(String file,String content,String encoding) throws IOException{

		createFolder(getFileFolder(file));

		FileOutputStream out = new FileOutputStream(file);
		OutputStreamWriter writer = new OutputStreamWriter(out,encoding);
		try{
			writer.write(content);
			return;
		}finally{
			try{
				writer.flush();
				writer.close();
				out.flush();
				out.close();
			}catch(Throwable e){}
		}
	}    

	/**
	 * 创建目录
	 * @param folder 目录全路径
	 */
	public static void createFolder(String folder){
		File file = new File(folder);
		if(!file.exists()){
			file.mkdirs();    
		}
	}
	/**
	 * 创建一个文件
	 * @param filePath
	 * @return
	 * @throws IOException
	 */
	public static String createFile(String filePath) throws IOException{
		if(StringUtils.isEmpty(filePath)){
			filePath = generateUniqueFileName("$$temp");
		}
		createFolder(getFileFolder(filePath));
		File f = new File(filePath);
		if(!f.exists()){
			f.createNewFile();
		}
		return filePath;
	}
	/**
	 * 为上传的文件生成唯一的文件名称
	 * @param fileName
	 * @return
	 */
	public static String generateUniqueFileName(String fileName) {
		DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");    
		String formatDate = format.format(new Date());    
		int random = new Random().nextInt(10000);    
		return formatDate + "_" + random + "@" + fileName;    
	}
	/**
	 * 获取上传到服务器上的文件的真正的名称
	 * @param uniqueFileName
	 * @return
	 */
	public static String getRealFileName(String uniqueFileName){
		if(StringUtils.isNotEmpty(uniqueFileName)){
			if(uniqueFileName.contains("@")){
				uniqueFileName = uniqueFileName.substring(uniqueFileName.lastIndexOf('@')+1);
			}else{
				uniqueFileName = getFileName(uniqueFileName);
			}
		}
		return uniqueFileName;
	}
	/**
	 * Copy bytes from an <code>InputStream</code> to an
	 * <code>OutputStream</code>.
	 *
	 * @param input  The <code>InputStream</code> to read from.
	 * @param output The <code>OutputStream</code> to write to.
	 *
	 * @return the number of bytes copied
	 *
	 * @throws IOException In case of an I/O problem
	 */
	public static int copy(InputStream input, OutputStream output)
	throws IOException {
		byte[] buffer = new byte[1024];
		int count = 0;
		int n = 0;
		while (-1 != (n = input.read(buffer))) {
			output.write(buffer, 0, n);
			count += n;
		}
		return count;
	}
	/**
	 * Return the mime type for a file name. The extension is parsed out and the
	 * method to get mime type by extension is called. Extension mappings are
	 * found in the mimeTypes.properties file in the org.extremecomponents.util
	 * package.
	 * @throws IOException 
	 */
	public static String getFileMimeType(String fileName) throws IOException {
		if (StringUtils.isBlank(fileName) || (fileName.indexOf(".") == -1)) {
			return null;
		}
		String extension = fileName.substring(fileName.lastIndexOf("."));

		if (StringUtils.isBlank(extension)) {
			return null;
		}

		initMimeType();

		extension = extension.toLowerCase();

		if (!extension.startsWith(".")) {
			extension = "." + extension;
		}
		return properties.getProperty(extension);

	}
	/**
	 * 对待下载/导出文件名称进行编码
	 * @param fileName
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String encodeFileName(String fileName) throws UnsupportedEncodingException{
		if(fileName == null || fileName.trim().equals("")) return "";
		return new String(fileName.getBytes(),EXPORTED_FILE_NAME_ENCODING);
	}

	private static synchronized void initMimeType() throws IOException{
		if(properties == null){
			properties = new Properties();
			properties.load(new ClassPathResource("mimeTypes.properties",FileHelper.class).getInputStream());
		}
	}
	/**
	 * 字符串替换
	 * @param template
	 * @param placeholder
	 * @param replacement
	 * @return
	 */
	public static String replace(String template, String placeholder, String replacement) {
		boolean wholeWords = false;
		int loc = template == null ? -1 : template.indexOf( placeholder );
		if ( loc < 0 ) {
			return template;
		}
		else {
			final boolean actuallyReplace = !wholeWords ||
			loc + placeholder.length() == template.length() ||
			!Character.isJavaIdentifierPart( template.charAt( loc + placeholder.length() ) );
			String actualReplacement = actuallyReplace ? replacement : placeholder;
			return new StringBuffer( template.substring( 0, loc ) )
			.append( actualReplacement )
			.append( replace( template.substring( loc + placeholder.length() ),
					placeholder,
					replacement) ).toString();
		}
	}

	/**
	 * 获取项目文件绝对路径
	 * @param file
	 * @return
	 */
	public static String getFilePath(String file){
		if(!file.contains(":")){
			File prjFile = new File(file);
			if(prjFile.exists() && prjFile.isDirectory()){
				return prjFile.getAbsolutePath();
			}
		}
		return file;
	}
	/**
	 * 得到类相应的目录路径
	 * @param clazz
	 * @return
	 */
	public static String getClassDiretory(Class<?> clazz){
		return "/" + clazz.getPackage().getName().replaceAll("\\.", "/")+"/";
	}



	/**
	 * 从jar包中读取文件
	 * @param fileName 待读取文件的文件名称
	 * @param relativeClass 和待读取文件在同一目录下的类
	 * @return 文件内容
	 * @throws IOException
	 */
	public static String readFileFromJar(String fileName,Class<?> relativeClass) throws IOException{

		String resourcePath = FileHelper.getClassDiretory(relativeClass)+fileName;
		InputStream raw = ResourceManager.class.getResource(resourcePath).openStream();
		if (raw == null){
			throw new IOException("Failed to find resource: " + fileName);
		}
		byte[] bit = new byte[raw.available()];
		raw.read(bit);
		return new String(bit,"UTF-8");


	}
	
	/**
     * 解压缩zip文件包，如有顶层目录则返回目录名;没有则返回空字符串
     * @param file
     * @param pathExtractTo
     * @param encoding zip
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
	public static void extractZipFile(File file,String pathExtractTo,String encoding) throws IOException{
        ZipFile zip = null;
        File f = null;
        try {
            zip = new ZipFile(file,encoding);
            Enumeration<ZipEntry> entries = zip.getEntries();
            while(entries.hasMoreElements()){
                ZipEntry entry = entries.nextElement();
                if(!entry.isDirectory()){
                	FileHelper.createFile(pathExtractTo + entry.getName(),zip.getInputStream(entry));
                	f= new File(pathExtractTo + entry.getName());
                	f.renameTo(new File(pathExtractTo + entry.getName().substring(entry.getName().lastIndexOf("/")+1)));
                }else{
                	FileHelper.createFolder(pathExtractTo + entry.getName());
                }
            }
        } finally{
        	if(null != zip){
                try{
                    zip.close();
                }catch(Exception e){//ignore
                }
            }
        }   
    }

}
